import 'dart:io';

import 'package:dart_frog_prod_server_hooks/dart_frog_prod_server_hooks.dart';
import 'package:mason/mason.dart';
import 'package:mocktail/mocktail.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

class _MockHookContext extends Mock implements HookContext {}

class _MockLogger extends Mock implements Logger {}

void main() {
  group('copyWorkspacePubspecLock', () {
    late List<int> exitCalls;
    late HookContext context;
    late Logger logger;
    late Directory projectDirectory;
    late Directory rootDirectory;

    setUp(() {
      exitCalls = [];
      context = _MockHookContext();
      logger = _MockLogger();
      rootDirectory = Directory.systemTemp.createTempSync('root');
      projectDirectory = Directory(
        path.join(rootDirectory.path, 'packages', 'project'),
      )..createSync(recursive: true);

      when(() => context.logger).thenReturn(logger);

      addTearDown(() {
        projectDirectory.delete().ignore();
        rootDirectory.delete().ignore();
      });
    });

    test('does nothing when pubspec.lock does not exist in workspace root', () {
      copyWorkspacePubspecLock(
        context,
        projectDirectory: projectDirectory.path,
        workspaceRoot: rootDirectory.path,
        exit: exitCalls.add,
      );
      expect(exitCalls, isEmpty);
      verifyNever(() => logger.err(any()));
      expect(projectDirectory.listSync(), isEmpty);
    });

    test('exits with error when unable to copy lockfile', () {
      const pubspecLockContents = '''
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
''';
      final file = File(path.join(rootDirectory.path, 'pubspec.lock'))
        ..writeAsStringSync(pubspecLockContents);
      Process.runSync('chmod', ['000', file.path]);
      copyWorkspacePubspecLock(
        context,
        projectDirectory: projectDirectory.path,
        workspaceRoot: rootDirectory.path,
        exit: exitCalls.add,
      );
      expect(exitCalls, equals([1]));
      verify(
        () => logger.err(any(that: contains('Permission denied'))),
      );
    });

    test('copies pubspec.lock to project directory when found', () {
      const pubspecLockContents = '''
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
''';
      File(path.join(rootDirectory.path, 'pubspec.lock'))
          .writeAsStringSync(pubspecLockContents);
      copyWorkspacePubspecLock(
        context,
        projectDirectory: projectDirectory.path,
        workspaceRoot: rootDirectory.path,
        exit: exitCalls.add,
      );
      expect(exitCalls, isEmpty);
      verifyNever(() => logger.err(any()));
      final projectDirectoryContents = projectDirectory.listSync();
      expect(projectDirectoryContents, hasLength(1));
      expect(
        projectDirectoryContents.first,
        isA<File>().having(
          (f) => path.basename(f.path),
          'name',
          'pubspec.lock',
        ),
      );
      expect(
        (projectDirectoryContents.first as File).readAsStringSync(),
        equals(pubspecLockContents),
      );
    });
  });
}
